using UnityEngine;

namespace UnityX
{
    [DisallowMultipleComponent]
    [RequireComponent(typeof(MeshFilter), typeof(MeshRenderer))]
    [AddComponentMenu("Effects/Model Line")]
    public class ModelLine : MonoBehaviour
    {
        private Mesh m_Mesh;
        private int m_PositionCount = 0;
        private Vector3[] m_Positions = new Vector3[100];

        public Material material
        {
            get { return GetComponent<MeshRenderer>().material; }
            set { GetComponent<MeshRenderer>().material = value; }
        }

        private void Awake()
        {
            m_Mesh = new Mesh();
            m_Mesh.indexFormat = UnityEngine.Rendering.IndexFormat.UInt32;
            GetComponent<MeshFilter>().mesh = m_Mesh;
        }

        public int positionCount
        {
            get { return m_PositionCount; }
            set
            {
                if (value > m_Positions.Length)
                {
                    Vector3[] p = new Vector3[value];
                    for (int i = 0; i < m_PositionCount; i++)
                    {
                        p[i] = m_Positions[i];
                    }
                    m_Positions = p;
                }
                m_PositionCount = value;
                Apply();
            }
        }

        public Vector3 GetPosition(int index)
        {
            return m_Positions[index];
        }
        public Vector3[] GetPositions()
        {
            if (m_Positions.Length == m_PositionCount)
            {
                return m_Positions;
            }
            Vector3[] positions = new Vector3[m_PositionCount];
            for (int i = 0; i < m_PositionCount; i++)
            {
                positions[i] = m_Positions[i];
            }
            return positions;
        }
        public void SetPosition(int index, Vector3 position)
        {
            m_Positions[index] = position;
            Apply();
        }
        public void SetPositions(Vector3[] positions)
        {
            if (positions.Length > m_Positions.Length)
            {
                m_Positions = new Vector3[positions.Length];
            }
            for (int i = 0; i < positions.Length; i++)
            {
                m_Positions[i] = positions[i];
            }
            m_PositionCount = positions.Length;
            Apply();
        }
        public void AddPosition(Vector3 position)
        {
            if (m_PositionCount >= m_Positions.Length)
            {
                Vector3[] newPositions = new Vector3[m_Positions.Length + 100];
                for (int i = 0; i < m_Positions.Length; i++)
                {
                    newPositions[i] = m_Positions[i];
                }
                m_Positions = newPositions;
            }
            m_Positions[m_PositionCount] = position;
            m_PositionCount++;
            Apply();
        }
        public void Simplify(float tolerance)
        {
            for (int i = 1; i < m_PositionCount - 1; i++)
            {
                if (Vector3.Distance(m_Positions[i - 1], m_Positions[i]) < tolerance)
                {
                    for (int j = i; j < m_PositionCount - 1; j++)
                    {
                        m_Positions[j] = m_Positions[j + 1];
                    }
                    m_PositionCount--;
                    i--;
                }
            }
            Apply();
        }
        public void Clear()
        {
            m_PositionCount = 0;
            Apply();
        }
        private void Apply()
        {
            m_Mesh.Clear();
            if (m_PositionCount < 2)
            {
                return;
            }
            m_Mesh.vertices = m_Positions;
            int[] ints = new int[m_PositionCount * 2];
            for (int i = 0; i < m_PositionCount - 1; i++)
            {
                ints[i * 2] = i;
                ints[i * 2 + 1] = i + 1;
            }
            m_Mesh.SetIndices(ints, MeshTopology.Lines, 0);
        }
    }
}